﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml;

namespace TweetMemeNET
{
    /// <summary>
    /// Base class for TweetMeme API results
    /// </summary>
    public abstract class TweetMemeResultBase : ITweetMemeResult
    {
        // The XML returned by the TweetMeme API
        protected XElement xml;

        // The status flag returned by the TweetMeme API
        protected TweetMemeStatus status = TweetMemeStatus.Undetermined;

        // Any status details returned by the TweetMeme API
        protected TweetMemeStatusDetails statusDetails = TweetMemeStatusDetails.None;

        /// <summary>
        /// Gets whether or not an API call was successful
        /// </summary>
        public virtual TweetMemeStatus Status
        {
            get { return status; }
            private set { status = value; }
        }

        /// <summary>
        /// Gets status details of this API result, if any
        /// </summary>
        public virtual TweetMemeStatusDetails StatusDetails
        {
            get { return statusDetails; }
            protected set { statusDetails = value; }
        }

        /// <summary>
        /// Instantiates a new TweetMemeResultBase object based on the specified XML result
        /// </summary>
        /// <param name="xml"></param>
        public TweetMemeResultBase(string xml)
        {
            if (string.IsNullOrEmpty(xml))
                throw new ArgumentNullException("Expected XML for the constructor, but the specified parameter was empty.");

            this.xml = XElement.Parse(xml);

            try
            {
                // Determine the status flag based on the XML returned by the TweetMeme API
                Status = GetResultStatus();

                // Get result details for error, if any
                if (Status==TweetMemeStatus.Failure)
                {
                    StatusDetails=GetResultStatusDetails();
                }
                else
                {
                    // Parse the XML returned by the TweetMeme API call
                    ParseResultXml();
                }
            }
            catch (XmlException)
            {
                // Indicate TweetMeme API failure
                Status=TweetMemeStatus.Failure;

                StatusDetails=TweetMemeStatusDetails.MalFormedXml;
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// Determines the status flag returned by the TweetMeme API
        /// </summary>
        /// <returns></returns>
        protected TweetMemeStatus GetResultStatus()
        {
            XElement statusElement = xml.Element(XName.Get("status", string.Empty));

            if (statusElement!=null)
            {
                string statusValue = statusElement.Value;

                switch (statusValue.ToLower())
                {
                    case "success":
                        return TweetMemeStatus.Success;
                    case "failure":
                        return TweetMemeStatus.Failure;
                    default:
                        return TweetMemeStatus.Undetermined;
                }
            }
            else
            {
                return TweetMemeStatus.Undetermined;
            }
        }

        /// <summary>
        /// Determines the status flag returned by the TweetMeme API
        /// </summary>
        /// <returns></returns>
        protected TweetMemeStatusDetails GetResultStatusDetails()
        {
            XElement reasonElement = xml.Element(XName.Get("reason", string.Empty));

            if (reasonElement!=null)
            {
                string reason = reasonElement.Value.ToLower();

                if (reason.StartsWith("unknown class of API call", StringComparison.InvariantCultureIgnoreCase))
                    return TweetMemeStatusDetails.UnknownClass;

                if (reason.StartsWith("unknown method", StringComparison.InvariantCultureIgnoreCase))
                    return TweetMemeStatusDetails.UnknownMethod;

                return TweetMemeStatusDetails.None;
            }
            else
            {
                return TweetMemeStatusDetails.None;
            }
        }

        /// <summary>
        /// Retrieves an element value from a TweetMeme story
        /// </summary>
        /// <param name="elementName"></param>
        /// <returns></returns>
        protected string GetStoryElementValue(string elementName)
        {
            return xml.Element(XName.Get("story", string.Empty)).Element(XName.Get(elementName, string.Empty)).Value;
        }

        /// <summary>
        /// Gets the full result element of XML returned by the TweetMeme API
        /// </summary>
        /// <returns></returns>
        protected XElement GetResultElement()
        {
            if (xml.Name.LocalName.Equals("result", StringComparison.InvariantCultureIgnoreCase))
                return xml;
            
            return xml.Element(XName.Get("result", string.Empty));
        }

        /// <summary>
        /// Parses the XML into a result item
        /// </summary>
        protected abstract void ParseResultXml();
    }
}
